Skip to content

hid: ipts: Fix double list_del race in ipts_mei_search() - #178

Open
joshuaspaulding wants to merge 1 commit into
linux-surface:v6.19-surface-develfrom
joshuaspaulding:ipts-fix-mei-search-race
Open

hid: ipts: Fix double list_del race in ipts_mei_search()#178
joshuaspaulding wants to merge 1 commit into
linux-surface:v6.19-surface-develfrom
joshuaspaulding:ipts-fix-mei-search-race

Conversation

@joshuaspaulding

@joshuaspaulding joshuaspaulding commented Sep 3, 2026

Copy link
Copy Markdown

Summary

ipts_mei_search() walks the received-message list under the read side of message_lock, drops the lock, then re-takes it for writing to unlink the entry it found. Two waiters for the same command code (typically the receiver poll thread and a userspace hidraw raw request, both inside ipts_control_send_feedback()) can each find the same entry during their read-locked walk and then both unlink and free it. The second list_del() hits LIST_POISON and, with CONFIG_DEBUG_LIST, oopses the poll kthread:

list_del corruption, ...->next is LIST_POISON1 (dead000000000100)
kernel BUG at lib/list_debug.c:56!
RIP: __list_del_entry_valid_or_report.cold
Call Trace:
 ipts_mei_search+0x83/0x150 [ipts]
 ipts_mei_recv+0x61/0x190 [ipts]
 ipts_cmd_recv_timeout+0x2f/0x90 [ipts]
 ipts_control_send_feedback+0x81/0xc0 [ipts]
 ipts_receiver_poll_loop.cold+0x89/0x11c [ipts]
 ipts_thread_runner+0x21/0x40 [ipts]

Without CONFIG_DEBUG_LIST it surfaces as a general protection fault on 0xdead000000000108 in ipts_mei_search(). The other caller is then stuck in D state inside the driver, so every later suspend fails with "tasks refusing to freeze" until reboot.

This is the same trace as linux-surface/linux-surface#2122 and linux-surface/intel-precise-touch#33.

The fix holds the write lock across the search and the unlink, so a message can only be claimed by one caller.

Testing

Surface Pro 7 (IPTS 045E:099F, EDS v2, poll mode). Reproduced on 6.12.107 with the stock patch series: oops on resume from s2idle while iptsd was being restarted, followed by an unfreezable iptsd for the rest of the boot. Rebuilt 6.12.107 with this change and ran repeated s2idle suspend/resume cycles with iptsd stopped before sleep and restarted on wake, which exercises the poll thread and the hidraw path concurrently. No oops, poll thread and iptsd healthy after every cycle.

The drivers/hid/ipts/mei.c in this branch is identical to the 6.12 series version, so the patch applies unchanged across the maintained branches.

ipts_mei_search() looks up a matching response under the read side of
message_lock, drops the lock, and then re-acquires it for writing to
unlink the entry. Two concurrent callers waiting for the same command
code (typically the receiver poll thread and a userspace hidraw raw
request, both inside ipts_control_send_feedback()) can each find the
same entry during their read-locked walk and then both unlink and free
it. The second list_del() hits LIST_POISON and, with CONFIG_DEBUG_LIST,
oopses the poll kthread:

  list_del corruption, ...->next is LIST_POISON1 (dead000000000100)
  kernel BUG at lib/list_debug.c:56!
  RIP: __list_del_entry_valid_or_report.cold
  Call Trace:
   ipts_mei_search+0x83/0x150 [ipts]
   ipts_mei_recv+0x61/0x190 [ipts]
   ipts_cmd_recv_timeout+0x2f/0x90 [ipts]
   ipts_control_send_feedback+0x81/0xc0 [ipts]
   ipts_receiver_poll_loop.cold+0x89/0x11c [ipts]
   ipts_thread_runner+0x21/0x40 [ipts]

Without CONFIG_DEBUG_LIST the same race shows up as a general
protection fault on 0xdead000000000108 in ipts_mei_search(). The other
caller is then left blocked in D state inside the driver, which makes
every later suspend fail with "tasks refusing to freeze". Seen on
resume from s2idle on a Surface Pro 7 while iptsd was (re)started.

Hold the write lock across the search and the unlink so that a message
can only be claimed by one caller.

Signed-off-by: Josh Spaulding <git@spaulding.app>
@joshuaspaulding
joshuaspaulding force-pushed the ipts-fix-mei-search-race branch from 4d5bc29 to f6df3e9 Compare September 3, 2026 02:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant